package com.zx.webflux.service;

import com.zx.webflux.dao.UserRepository;
import com.zx.webflux.model.User;
import com.zx.webflux.wrapper.PageWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * description:  <br>
 * create: 2024-08-16 21:37
 * </p>
 *
 * @author zhou  xun
 */
@Service
public class UserService {

    private final UserRepository userRepository;
    private final DatabaseClient databaseClient;
    private final R2dbcEntityTemplate r2dbcEntityTemplate;

    @Autowired
    public UserService(UserRepository userRepository, DatabaseClient databaseClient, R2dbcEntityTemplate r2dbcEntityTemplate) {
        this.userRepository = userRepository;
        this.databaseClient = databaseClient;
        this.r2dbcEntityTemplate = r2dbcEntityTemplate;
    }

    private static Mono<PageWrapper<User>> getMap(Mono<List<User>> usersMono, Mono<Long> countMono, PageWrapper<User> result, Pageable pageable) {
        return Mono.zip(usersMono, countMono)
                .map(tuple -> {
                    result.setTotal(Math.toIntExact(tuple.getT2()));
                    result.setData(tuple.getT1());
                    result.setCurrentPageNum(pageable.getPageNumber());
                    result.setPageSize(pageable.getPageSize());
                    result.setTotalPage(pageable.getPageSize());
                    return result;
                });
    }

    public Mono<User> findUserById(Long id) {
        return userRepository.findById(id);
    }

    public Flux<User> findAllUsers() {
        return userRepository.findAll();
    }

    /**
     * 根据ID列表和分页参数获取用户列表
     *
     * @param pageNum  当前页码
     * @param pageSize 每页显示数量
     * @param ids      以逗号分隔的用户ID列表
     * @return 分页结果
     */
    public Mono<PageWrapper<User>> getUsers(Integer pageNum, Integer pageSize, String ids) {
        // 初始化分页结果包装类
        PageWrapper<User> result = new PageWrapper<>();

        // 校验分页参数
        Pageable pageable;
        try {
            pageable = PageRequest.of(pageNum, pageSize);
        } catch (Exception e) {
            result.fail(e.getMessage());
            return Mono.just(result);
        }

        // 校验IDs参数
        if (ids == null || ids.trim().isEmpty()) {
            result.fail("入参ids不能为空!");
            return Mono.just(result);
        }

        // 将字符串IDs转换为List
        List<String> idList = Arrays.asList(ids.split(","));
        if (idList.isEmpty()) {
            result.fail("入参ids必须包含至少一个以逗号分隔的数据!");
            return Mono.just(result);
        }

        // 异步查询总记录数
        Mono<Long> countMono = r2dbcEntityTemplate.select(User.class)
                .from("users")
                .matching(Query.query(Criteria.where("id").in(idList)))
                .count();

        // 异步查询分页数据
        Mono<List<User>> usersMono = r2dbcEntityTemplate.select(User.class)
                .from("users")
                .matching(Query.query(Criteria.where("id").in(idList)).with(pageable))
                .all()
                .collectList();

        // 合并总记录数和分页数据，并设置到结果中
        return getMap(usersMono, countMono, result, pageable);
    }

    public Mono<PageWrapper<User>> getPageUsers(Integer pageNum, Integer pageSize) {
        // 初始化分页结果包装类
        PageWrapper<User> result = new PageWrapper<>();

        // 校验分页参数
        Pageable pageable;
        try {
            pageable = PageRequest.of(pageNum, pageSize);
        } catch (Exception e) {
            result.fail(e.getMessage());
            return Mono.just(result);
        }

        // 异步查询总记录数
        Mono<Long> countMono = r2dbcEntityTemplate.select(User.class)
                .from("users")
                .matching(Query.query(Criteria.empty()))
                .count();
        // 异步查询分页数据
        Mono<List<User>> usersMono = r2dbcEntityTemplate.select(User.class)
                .from("users")
                .matching(Query.query(Criteria.empty()).with(pageable))
                .all()
                .collectList();
        // 合并总记录数和分页数据，并设置到结果中
        return getMap(usersMono, countMono, result, pageable);
    }
}
